﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using XunitExt;
using System.Collections.Specialized;

namespace Rarous.NForms.Test {
  public class FormTests {

    private Form _form;

    /// <summary>
    /// Initializes a new instance of the FormTests class.
    /// </summary>
    public FormTests() {
      _form = new Form();
    }

    private static TestForm GetFormWithData() {
      var data = new NameValueCollection();
      data.Add("text", "test");
      data.Add("text2", "test");

      var form = new TestForm(data);
      return form;
    }

    private static TestForm GetFormWithoutData() {
      var form = new TestForm(new NameValueCollection());
      return form;
    }

    [Fact]
    public void Form_empty_constructor_should_preset_data_and_messages_collections() {
      var form = new Form();

      form.Messages.ShouldNotBeNull();
      form.Messages.ShouldBeEmpty();

      form.Data.ShouldNotBeNull();
      form.Data.ShouldBeEmpty();
    }

    [Fact]
    public void Form_constructor_should_load_data() {
      var form = GetFormWithData();

      form.Data.ShouldNotBeNull();
      form.Data.ShouldNotBeEmpty();

      form.Messages.ShouldNotBeNull();
      form.Messages.ShouldBeEmpty();

      form["text"].GetValue().ShouldEqual("test");
      form["text2"].GetValue().ShouldEqual("test");
    }

    [Fact]
    public void Form_constructor_should_load_data_and_messages() {
      var data = new NameValueCollection();
      data.Add("test", "test");

      var messages = new List<string> { "chybova hlaska" };

      var form = new Form(data, messages);

      form.Data.ShouldNotBeNull();
      form.Data.ShouldNotBeEmpty();

      form.Messages.ShouldNotBeNull();
      form.Messages.ShouldNotBeEmpty();

      form.ValidationSummary.ToString().ShouldNotEqual(String.Empty);
    }

    [Fact]
    public void Form_data_with_empty_values_should_return_empty_string() {
      var data = new NameValueCollection();
      data.Add("email", "@");

      var form = new TestForm(data);

      form["email"].GetValue().ShouldEqual(String.Empty);
    }

    [Fact]
    public void Form_data_should_be_converted_to_other_data_types() {
      var data = new NameValueCollection();
      data.Add("text", "112");

      var form = new TestForm(data);

      form["text"].GetValue<int>(Convert.ToInt32).ShouldEqual(112);
    }

    [Fact]
    public void Form_data_should_be_converted_to_other_data_types_empty_value_to_default() {
      var data = new NameValueCollection();
      data.Add("num", "13");

      var form = new TestForm(data);

      form["num"].GetValue<int>(Convert.ToInt32).ShouldEqual(default(int));
    }

    [Fact]
    public void Form_fields_without_data_should_have_empty_value() {
      TestForm form = GetFormWithoutData();

      form["text"].GetValue().ShouldEqual(String.Empty);
      form["text2"].GetValue().ShouldEqual(String.Empty);
    }

    [Fact]
    public void Form_validate_required_field_should_be_valid_with_data() {
      var form = GetFormWithData();

      form.Validate();

      form.IsValid.ShouldBeTrue();
    }

    [Fact]
    public void Form_validate_required_field_should_not_be_valid_without_data() {
      var form = GetFormWithoutData();

      form.Validate();

      form.IsValid.ShouldBeFalse();
    }

    [Fact]
    public void Form_validation_summary_without_messages_should_not_render() {
      var form = new Form();

      form.ValidationSummary.ToString().ShouldEqual(String.Empty);
    }

    [Fact]
    public void Form_should_add_hidden_field() {
      var hidden = _form.AddHidden("hidden");

      _form["hidden"].ShouldBeSameAs(hidden);
    }

    [Fact]
    public void Form_should_add_text_field() {
      var text1 = _form.AddText("text1", "test");
      var text2 = _form.AddText("text2", "test", 30);
      var text3 = _form.AddText("text3", "test", 30, 60);

      _form["text1"].ShouldBeSameAs(text1);

      _form["text2"].ShouldBeSameAs(text2);
      _form["text2"].Control["Size"].ShouldEqual("30");

      _form["text3"].ShouldBeSameAs(text3);
      _form["text3"].Control["Size"].ShouldEqual("30");
      _form["text3"].Control["MaxLength"].ShouldEqual("60");
    }

    [Fact]
    public void Form_should_add_text_area() {
      var textArea1 = _form.AddTextArea("text1", "test");
      var textArea2 = _form.AddTextArea("text2", "test", 25, 38);

      _form["text1"].ShouldBeSameAs(textArea1);

      _form["text2"].ShouldBeSameAs(textArea2);
      _form["text2"].Control["Rows"].ShouldEqual("25");
      _form["text2"].Control["Cols"].ShouldEqual("38");
    }

    [Fact]
    public void Form_should_add_password_field() {
      var password1 = _form.AddPassword("text1", "test");
      var password2 = _form.AddPassword("text2", "test", 30, 60);
      var password3 = _form.AddPassword("text3", "test", new object());

      _form["text1"].ShouldBeSameAs(password1);
      _form["text1"].Control["Type"].ShouldEqual("Password");

      _form["text2"].ShouldBeSameAs(password2);
      _form["text2"].Control["Size"].ShouldEqual("30");
      _form["text2"].Control["MaxLength"].ShouldEqual("60");

      _form["text3"].ShouldBeSameAs(password3);
    }

    [Fact]
    public void Form_should_add_checkbox() {
      var check1 = _form.AddCheckBox("check1", "test");
      var check2 = _form.AddCheckBox("check2", "test", true);
      var check3 = _form.AddCheckBox("check3", "test", false);

      _form["check1"].ShouldBeSameAs(check1);

      _form["check2"].ShouldBeSameAs(check2);
      _form["check2"].Control["Checked"].ShouldEqual("checked");
      _form["check2"].Label.Text.ShouldEqual("test");

      _form["check3"].ShouldBeSameAs(check3);
      _form["check3"].Control["Checked"].ShouldBeNull();
      _form["check3"].Label.Text.ShouldEqual("test");
    }

    [Fact]
    public void Form_should_add_radio() {
      var radio = _form.AddRadio("radio1", "test", new ListItem[0]);

      _form["radio1"].ShouldBeSameAs(radio);
    }

    [Fact]
    public void Form_should_add_button() {
      var button = _form.AddButton("button", "test");

      _form["button"].ShouldBeSameAs(button);
      _form["button"].Control["Type"].ShouldEqual("Button");
      _form["button"].Control["Value"].ShouldEqual("test");
    }

    [Fact]
    public void Form_should_add_submit() {
      var submit = _form.AddSubmit("button", "test");

      _form["button"].ShouldBeSameAs(submit);
      _form["button"].Control["Type"].ShouldEqual("Submit");
      _form["button"].Control["Value"].ShouldEqual("test");
    }

    [Fact]
    public void Form_should_add_reset() {
      var reset = _form.AddReset("button", "test");

      _form["button"].ShouldBeSameAs(reset);
      _form["button"].Control["Type"].ShouldEqual("Reset");
      _form["button"].Control["Value"].ShouldEqual("test");
    }

    [Fact]
    public void Form_should_add_image_button() {
      var imgButton = _form.AddImage("image", "url");

      _form["image"].ShouldBeSameAs(imgButton);
      _form["image"].Control["Type"].ShouldEqual("Image");
      _form["image"].Control["Src"].ShouldEqual("url");
    }

    [Fact]
    public void Form_should_add_select() {
      var select = _form.AddSelect("select", "test", new ListItem[0]);

      _form["select"].ShouldBeSameAs(select);
    }

    [Fact]
    public void Form_should_render() {
      var form = GetFormWithData();

      string renderedForm = form.Render();

      renderedForm.ShouldNotBeNull();
      renderedForm.Contains("<form").ShouldBeTrue();
      renderedForm.Contains("<input").ShouldBeTrue();
      renderedForm.Contains("<textarea").ShouldBeTrue();
    }

    private class TestForm : Form {
      /// <summary>
      /// Initializes a new instance of the TestForm class.
      /// </summary>
      public TestForm(NameValueCollection data) 
        : base(data) {
        CreateFields();
        BindData();
      }

      private void CreateFields() {
        AddText("text", "text1").
          Required("Text je povinny");
        AddText("num", "cislo").
          SetEmptyValue(13);
        AddText("email", "e-mail").
          SetEmptyValue("@");
        AddTextArea("text2", "text2").
          Required("povinne").
          AddMinimalLengthRule(3, "text musi byt delsi nez tri znaky");
      }
    }
  }
}
